﻿יצירת הרחבות
===================

מאחר והרחבות נועדו לשימוש על ידי מפתחים אחרים, יצירה שלהם דורשת מאמץ נוסף. להלן כמה הנחיות כלליות:

* הרחבה צריכה להיות נפרדת. כלומר, התלות החיצונית שלה צריכה להיות מינימלית. זה יהיה כאב ראש למשתמשים אם הרחבה תדרוש התקנה של חבילות נוספות, מחלקות או קבצים.
* קבצים הקשורים להרחבה צריכים להיות מסודרים תחת אותה תיקיה ששמה הוא שם ההרחבה.
* שמות המחלקות בהרחבה צריכות להיות מוגדרת עם קידומת כלשהי בכדי להבדיל אותם ממחלקות של הרחבות נוספות.
* הרחבה צריכה להגיע ולהכיל מידע אודות ההתקנה ושימוש בהרחבה (דוקומנטציה). זה יחסוך זמן ומאמץ של מפתחים אחרים שצריכים להשתמש בהרחבה.
* הרחבה צריכה לכלול רישיון מתאים. במידה והינך רוצה שיהיה ניתן להשתמש בהרחבה בפרוייקטים פתוחים וסגורים, יש לשקול שימוש ברישיון מסוג BSD, MIT וכדומה, לא GPL מאחר והוא דורש שהקוד שמריץ אותו יהיה פתוח גם כן.

בחלק זה, אנו מסבירים כיצד ניתן ליצור הרחבות חדשות, לפי הקטגוריות המתוארות [סקירה](/doc/guide/extension.overview).
תיאורים אלו תקפים גם לרכיבים שהינך יוצר לפרוייקטים שלך בלבד.

רכיב אפליקציה
---------------------

[רכיב אפליקציה](/doc/guide/basics.application#application-component) צריך ליישם את הממשק [IApplicationComponent] או להיות תת-מחלקה (לירוש) של [CApplicationComponent]. המתודה העיקרית שצריך ליישם הינה [IApplicationComponent::init] שבה הרכיב מבצע עבודות אתחול. מתודה זו רצה לאחר היצור של הרכיב והמאפיינים ההתחלתיים (המוגדרים [בהגדרות האפליקציה](/doc/guide/basics.application#application-configuration)) מצורפים.

כברירת מחדל, רכיב אפליקציה נוצר ומאותחל רק ברגע שניגשים אליו בפעם הראשונה בזמן ניהול הבקשה. במידה ויש ליצור רכיב אפליקציה לאחר יצירת האובייקט של האפליקציה, מומלץ לדרוש מהמשתמש להגדיר את המזהה היחודי שלו במאפיין [CApplication::preload].

התנהגות
--------

בכדי ליצור התנהגות, יש ליישם את הממשק [IBehavior]. לנוחות, Yii מספקת מחלקת בסיס [CBehavior] אשר כבר מיישמת את הממשק הנחוץ ומספקת כמה מתודות שימושיות נוספות. תת-מחלקות צריכות ליישם את המתודות הנוספות שעומדות להיות זמינות לרכיבים אליהם הם יצורפו.

כשמפתחים התנהגות עבור [CModel] ו [CActiveRecord], ניתן להרחיב מהמחלקות [CModelBehavior] ו [CActiveRecordBehavior], בהתאמה. מחלקות בסיס אלו מציעות אפשרויות נוספות שמיועדות ספציפית ל [CModel] ו [CActiveRecord]. לדוגמא, המחלקה [CActiveRecordBehavior] מיישמת סט של מתודות המגיבות לאירועים אשר מתבצעים במחלקת ActiveRecord.

הקוד הבא מציג דוגמא להתנהגות של ActiveRecord. כשההתנהגות מצורפת לאובייקט של  AR וכשהאובייקט AR נשמר על ידי קריאה למתודה `save()`, הוא אוטומטית יגדיר את המאפיינים `create_time` ו `update_time` עם הזמן הנוכחי בשרת.

~~~
[php]
class TimestampBehavior extends CActiveRecordBehavior
{
    public function beforeSave($event)
    {
        if($this-»owner-»isNewRecord)
            $this-»owner-»create_time=time();
        else
            $this-»owner-»update_time=time();
    }
}
~~~


וידג'ט
------

[וידג'ט](/doc/guide/basics.view#widget) צריך להיות תת מחלקה של [CWidget] או מחלקות היורשות ממנה.

הדרך הקלה ביותר ליצור וידג'ט היא על ידי הרחבת וידג'ט קיים, דריסה של מתודות הנמצאות בו והגדרת המאפיינים הראשיים שלו. לדוגמא, במידה והינך רוצה לעבוד עם סגנון CSS שונה עבור [CTabView], ניתן להגדיר את המאפיין שלו [CTabView::cssFile] בזמן השימוש בוידג'ט. כמו כן ניתן להרחיב את המחלקה שלו [CTabView] בצורה הבאה בכדי שלא תצטרך להגדיר מאפיין זה בכל פעם שהינך משתמש בוידג'ט.

~~~
[php]
class MyTabView extends CTabView
{
    public function init()
    {
        if($this-»cssFile===null)
        {
            $file=dirname(__FILE__).DIRECTORY_SEPARATOR.'tabview.css';
            $this-»cssFile=Yii::app()-»getAssetManager()-»publish($file);
        }
        parent::init();
    }
}
~~~

בקוד למעלה, אנו דורסים את המתודה [CWidget::init] ומציבים למאפיין [CTabView::cssFile] את סגנון CSS ברירת המחדל במידה והוא לא הוגדר ספציפית. אנו מוסיפים את קובץ הסגנון תחת התיקיה הנוכחית בה נמצאת המחלקה `MyTabView` בכדי שיהיה ניתן לאחד אותם כהרחבה. מאחר וקובץ הסגנון הוא לא נגיש לווב יהיה צורך בלפרסם אותו בקובץ נכס.

בכדי ליצור וידג'ט חדש מהתחלה, אנו בעיקר צריכים ליישם שני מתודות: [CWidget::init] ו [CWidget::run]. הראשונה רצה כשאנו משתמשים ב `this-»beginWidget$` בכדי להוסיף את הוידג'ט לתצוגה, והשני רץ ברגע שאנו קוראים ל `this-»endWidget$`.
במידה ואנו רוצים לתפוס את התוכן הנמצא בין שני המתודות הללו, אנו יכולים להתחיל [בפקודת תפסית תצוגה](http://us3.php.net/manual/en/book.outcontrol.php) במתודה [CWidget::init] ולקבל את התוכן שנתפס על ידי [CWidget::run] להמשך העיבוד.

בדרך כלל וידג'ט דורש הוספה של קבצי CSS, JS וקבצים נוספים בעמוד אשר הוידג'ט משתמש בהם. אנו קוראים לקבצים אלו *נכסים* מאחר והם נשארים ביחד עם המחלקה של הוידג'ט ובדרך כלל לא ניתן לגשת אליהם דרך ממשק הווב. בכדי לאפשר גישה לקבצים אלו דרך הווב, אנו צריכים לפרסם אותם לתיקיה בה יש גישה לווב בעזרת [CWebApplication::assetManager], כפי שמוצג בקוד למעלה. חוץ מזה, שבמידה ואנו רוצים לפרסם קובץ CSS או JS אנו צריכים לרשום אותו על ידי שימוש במחלקה [CClientScript].

~~~
[php]
class MyWidget extends CWidget
{
    protected function registerClientScript()
    {
        // ..פרסום קבצי CSS ו JS כאן...
        $cs=Yii::app()-»clientScript;
        $cs-»registerCssFile($cssFile);
        $cs-»registerScriptFile($jsFile);
    }
}
~~~

וידג'ט יכול להכיל קבצי תצוגה משלו. במקרה זה, יש ליצור תיקיה בשם `views` תחת התיקיה המכילה את קובץ המחלקה של הוידג'ט, ויש לשמור את כל קבצי התצוגה של הוידג'ט בתיקיה זו. במחלקה של וידג'ט, בכדי לטעון קובץ תצוגה של הוידג'ט, יש להשתמש ב `$this-»render('viewName')`, בדומה למה שעושים בקונטרולר.

פעולה
------

מחלקת [פעולה](/doc/guide/basics.controller#action) צריכה להיות תת-מחלקה של [CAction] או מחלקות היורשות ממנה. המתודה העיקרית שצריך ליישם לפעולה הינה [IAction::run].

פילטר
------

[פילטר](/doc/guide/basics.controller#filter) צריך להיות תת מחלקה של [CFilter] או מחלקות היורשות ממנה. המתודות העיקריות שצריך ליישם לפילטר הם [CFilter::preFilter] ו [CFilter::postFilter]. הראשון רץ לפני שהפעולה בקונטרולר מתבצעת בזמן שהשני לאחר הפעולה.

~~~
[php]
class MyFilter extends CFilter
{
    protected function preFilter($filterChain)
    {
        // לוגיקה שרצה לפני שהפעולה בקונטרולר רצה
        return true; // יש להחזיר false במידה ורוצים לבטל את הרצת הפעולה
    }

    protected function postFilter($filterChain)
    {
        // לוגיקה שרצה לאחר הרצת הפעולה בקונטרולר
    }
}
~~~

הפרמטר `filterChain$` הוא אובייקט של [CFilterChain] המכיל מידע אודות הפעולה בקונטרולר שכרגע עוברת בתוך הפילטר.

קונטרולר
----------

[קונטרולר](/doc/guide/basics.controller) המופץ בתור הרחבה המחלקה שלו צריכה להיות תת של [CExtController], במקום [CController]. הסיבה העיקרית הינה ש [CController] מניח שקבצי התצוגה של הקונטרולר נמצאים תחת `application.views.controllerID`, בזמן ש [CExtController] מניח שקבצי התצוגה של הקונטרולר נמצאים תחת התיקיה `views` שהינה תת תיקיה של התיקיה בה נמצא קובץ המחלקה של הקונטרולר. לכן, קל יותר להפיץ את הקונטרולר מאחר וקבצי התצוגה שלו נשארים ביחד עם קובץ המחלקה של הקונטרולר.

ולידטור (אימות נתונים)
---------

ולידטור צריך להיות תת-מחלקה של [CValidator] וליישם את המתודה [CValidator::validateAttribute].

~~~
[php]
class MyValidator extends CValidator
{
    protected function validateAttribute($model,$attribute)
    {
        $value=$model-»$attribute;
        if($value has error)
            $model-»addError($attribute,$errorMessage);
    }
}
~~~

מסוף פקודות
---------------

[פקודת מסוף](/doc/guide/topics.console) צריכה לירוש מהמחלקה [CConsoleCommand] וליישם את המתודה [CConsoleCommand::run]. בנוסף, ניתן לדרוס את המתודה [CConsoleCommand::getHelp] בכדי לספק מידע אודות השימוש בפקודה.

~~~
[php]
class MyCommand extends CConsoleCommand
{
    public function run($args)
    {
        // הפרמטר היחידה בפונקציה זו מחזיר מערך עם המידע שהוזן לפקודה
    }

    public function getHelp()
    {
        return 'הסבר כיצד להריץ פקודה זו';
    }
}
~~~

מודול
------

אנא קרא את החלק אודות מודולים המסביר כיצד לייצר מודול.

הנחייה כללית לפיתוח מודול הינה שהמודול צריך להיות חלק בפני עצמו. קבצי משאבים (כמו קבצי JS, CSS ותמונות) אשר המודול משתמש בהם צריכים להגיע ביחד עם המודול. והמודול צריך לפרסם אותם כדי שיהיה ניתן לגשת אליהם דרך הווב (עמוד האינטרנט).

רכיב כללי
-----------------

פיתוח הרחבה שהינה רכיב כללי זה כמו לכתוב מחלקה. שוב, הרכיב צריך לעמוד בפני עצמו בכדי שמפתחים אחרים יוכלו להשתמש בו.

«div class="revision"»$Id: extension.create.txt 1423 2009-09-28 01:54:38Z qiang.xue $«/div»